
package com.wulian.user.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.wulian.common.constants.CommonConstants;
import com.wulian.common.constants.UserConstant;
import com.wulian.common.dto.SysUserDto;
import com.wulian.common.dto.UserInfo;
import com.wulian.common.entity.AppResultMoudel;
import com.wulian.common.entity.CarSysUser;
import com.wulian.common.entity.SysUser;
import com.wulian.common.entity.SysUserDataPermission;
import com.wulian.common.util.JSONUtil;
import com.wulian.common.util.MD5;
import com.wulian.common.util.Query;
import com.wulian.common.util.RegUtil;
import com.wulian.common.vo.MenuVO;
import com.wulian.common.vo.ResultMoudel;
import com.wulian.common.vo.SysRole;
import com.wulian.common.vo.UserVO;
import com.wulian.user.entity.*;
import com.wulian.user.mapper.*;
import com.wulian.user.service.SysMenuService;
import com.wulian.user.service.SysTreeService;
import com.wulian.user.service.SysUserRoleService;
import com.wulian.user.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author Administrator
 * @date 2018/6/31
 */
@Slf4j
@Service
@Transactional
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {
	private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder();
	@Autowired
	private SysMenuService sysMenuService;
	@Autowired
	private RedisTemplate redisTemplate;
	@Autowired
	private SysUserMapper sysUserMapper;
	@Autowired
	private SysUserRoleService sysUserRoleService;
	@Autowired
	private SysUserService userService;
	@Autowired
	private SysUserDataPermissionMapper sysUserDataPermissionMapper;
	@Autowired
	private SysTreeService sysTreeService;
	@Autowired
	private PostUserMapper postUserMapper;
	@Autowired
	private CompanyManagerMapper companyManagerMapper;
	@Autowired
	private SysDictMapper sysDictMapper;
	@Autowired
	private StringRedisTemplate stringRedisTemplate;

	@Override
	public UserInfo findUserInfo(UserVO userVo) {
		SysUser condition = new SysUser();
		condition.setUsername(userVo.getUsername());
		SysUser sysUser = this.selectOne(new EntityWrapper<>(condition));

		UserInfo userInfo = new UserInfo();
		userInfo.setSysUser(sysUser);
		// 设置角色列表
		List<SysRole> roleList = userVo.getRoleList();
		List<String> roleNames = new ArrayList<>();
		if (CollectionUtils.isNotEmpty(roleList)) {
			for (SysRole sysRole : roleList) {
				if (!org.apache.commons.lang3.StringUtils.equals(CommonConstants.BASE_ROLE, sysRole.getRoleName())) {
					roleNames.add(sysRole.getRoleName());
				}
			}
		}
		String[] roles = roleNames.toArray(new String[roleNames.size()]);
		userInfo.setRoles(roles);

		// 设置权限列表（menu.permission）
		Set<MenuVO> menuVoSet = new HashSet<>();
		for (String role : roles) {
			List<MenuVO> menuVos = sysMenuService.findMenuByRoleName(role);
			menuVoSet.addAll(menuVos);
		}
		Set<String> permissions = new HashSet<>();
		for (MenuVO menuVo : menuVoSet) {
			if (StringUtils.isNotEmpty(menuVo.getPermission())) {
				String permission = menuVo.getPermission();
				permissions.add(permission);
			}
		}
		userInfo.setPermissions(permissions.toArray(new String[permissions.size()]));
		return userInfo;
	}

	@Override
	public UserVO findUserByUsername(Map<String, Object> paramMap) {
		return sysUserMapper.selectUserVoByUsername(paramMap);
	}

	/**
	 * 通过手机号查询用户信息
	 *
	 * @param mobile
	 *            手机号
	 * @return 用户信息
	 */
	@Override
	@Cacheable(value = "user_details_mobile", key = "#mobile")
	public UserVO findUserByMobile(String mobile) {
		return sysUserMapper.selectUserVoByMobile(mobile);
	}

	/**
	 * 通过openId查询用户
	 *
	 * @param openId
	 *            openId
	 * @return 用户信息
	 */
	@Override
	@Cacheable(value = "user_details_openid", key = "#openId")
	public UserVO findUserByOpenId(String openId) {
		return sysUserMapper.selectUserVoByOpenId(openId);
	}

	@Override
	public Page selectWithRolePage(Query query, UserVO userVO) {
		Map<String, Object> params = query.getCondition();
		Object isrelate =  params.containsKey("isrelate") ? params.get("isrelate"): null;
		Integer isrelate_num = 0;
		//获取当前用户所属部门ID
		if (isrelate != null)
			isrelate_num = (Integer) isrelate;
		else
			isrelate_num = 1;

		if (isrelate_num == 1){
			SysTree sysTree = new SysTree();
			sysTree.setTypeId(2);
			sysTree.setChriledId(Long.valueOf(userVO.getDeptId()));
			//获取当前用户所属部门下所有的部门信息
			List<SysTree> selectListChannel = sysTreeService.selectListChannel(sysTree);
			//转换为List<String>
			List<String> deptIdList = selectListChannel.stream()
					.map(st -> String.valueOf(st.getChriledId())).collect(Collectors.toList());
			//为避免deptIdList数据太大转换为字符串,以“,”号隔开,方便下面数据读取
			String deptIds = deptIdList.stream().collect(Collectors.joining(","));
			params.put("deptIds", deptIds);
			List selectUserVoByPage = sysUserMapper.selectUserVoPageDataScope(query, params);
			query.setRecords(selectUserVoByPage);
			return query;
		}else{
			params.put("deptIds", userVO.getDeptId().toString());
			List selectUserVoByPage = sysUserMapper.selectUserVoPageDataScope(query, params);
			query.setRecords(selectUserVoByPage);
			return query;
		}

	}

	/**
	 * 通过ID查询用户信息
	 *
	 * @param id
	 *            用户ID
	 * @return 用户信息
	 */
	@Override
	public UserVO selectUserVoById(Integer id) {
		return sysUserMapper.selectUserVoById(id);
	}

	@Override
	public ResultMoudel updateUserStatus(SysUser user) {
		Boolean flag = this.updateById(user);
		if (flag) {
			return new ResultMoudel(ResultMoudel.SUCCESS_FLAG, "修改成功");
		}

		return new ResultMoudel("error", "修改失败");

	}

	@Override
	public Long selectempDeptIdByWorkNumber(String workNumber) {
		return Long.parseLong(sysUserMapper.selectempDeptIdByWorkNumber(workNumber).toString());
	}

	@Override
	public Boolean updateDeptIdByWorkNumber(SysUser sysUser) {
		return sysUserMapper.updateDeptIdByWorkNumber(sysUser);
	}

	/**
	 * 保存用户验证码，和randomStr绑定
	 *
	 * @param randomStr
	 *            客户端生成
	 * @param imageCode
	 *            验证码信息
	 */
	@Override
	public void saveImageCode(String randomStr, String imageCode) {
		redisTemplate.opsForValue().set(CommonConstants.DEFAULT_CODE_KEY + randomStr, imageCode,
				CommonConstants.DEFAULT_IMAGE_EXPIRE, TimeUnit.SECONDS);
	}

	/**
	 * 发送验证码
	 * <p>
	 * 1. 先去redis 查询是否 60S内已经发送 2. 未发送： 判断手机号是否存 ? false :产生4位数字 手机号-验证码 3.
	 * 发往消息中心-》发送信息 4. 保存redis
	 *
	 * @param mobile
	 *            手机号
	 * @return true、false
	 */
	@Override
	public ResultMoudel sendSmsCode(String mobile) {
		SysUser params = new SysUser();
		params.setPhone(mobile);
		List<SysUser> userList = this.selectList(new EntityWrapper<>(params));

		if (CollectionUtils.isEmpty(userList)) {
			log.error("根据用户手机号{}查询用户为空", mobile);
			return new ResultMoudel<>(ResultMoudel.ERROR_FLAG, "手机号不存在");
		}

		String code = RandomUtil.randomNumbers(4);
		JSONObject contextJson = new JSONObject();
		contextJson.put("code", code);
		contextJson.put("product", "");
		log.info("短信发送请求消息中心 -> 手机号:{} -> 验证码：{}", mobile, code);
		redisTemplate.opsForValue().set(CommonConstants.DEFAULT_CODE_KEY + mobile, code,
				CommonConstants.DEFAULT_IMAGE_EXPIRE, TimeUnit.SECONDS);
		return new ResultMoudel<>(ResultMoudel.SUCCESS_FLAG, "发送验证码成功");
	}

	/**
	 * 删除用户
	 *
	 * @param sysUser
	 *            用户
	 * @return Boolean
	 */
	@Override
	public Boolean deleteUserById(SysUser sysUser,SysUser updateUser) {
		//sysUserRoleService.deleteByUserId(sysUser.getUserId());
		//this.deleteById(sysUser.getUserId());
		Date date = new Date();
		sysUser.setUpdateTime(date);
		sysUser.setUpdateId(updateUser.getUserId());
		sysUser.setDelFlag(CommonConstants.DEL_FLAG_YES);
		SysUser whereUser  = new SysUser();
		whereUser.setUserId(sysUser.getUserId());
		whereUser.setCompanyId(updateUser.getCompanyId());
		EntityWrapper where  = new EntityWrapper(whereUser);
		sysUser.setUsername(null);
		boolean update = this.update(sysUser, where);
		return update;
	}
  
	@Override
	@CacheEvict(value = "user_details", key = "#username")
	public ResultMoudel updateUserInfo(SysUserDto userDto, String username) {
		Map<String, Object> paramMap = new HashMap<String, Object>();
		paramMap.put("username", username);
		UserVO userVo = this.findUserByUsername(paramMap);
		SysUser sysUser = new SysUser();
		if (StrUtil.isNotBlank(userDto.getPassword()) && StrUtil.isNotBlank(userDto.getNewpassword1())) {
			if (MD5.sign(userDto.getPassword(), null, "utf-8").equals(userVo.getPassword())) {
				sysUser.setPassword(MD5.sign(userDto.getNewpassword1(), null, "utf-8"));
			} else {
				log.warn("原密码错误，修改密码失败:{}", username);
				return new ResultMoudel("error", "原密码错误，修改失败");
			}
		}
		sysUser.setPhone(userDto.getPhone());
		sysUser.setUserId(userVo.getUserId());
		sysUser.setAvatar(userDto.getAvatar());
		sysUser.setName(userDto.getName());
		sysUser.setEmail(userDto.getEmail());
		sysUser.setStatus(userDto.getStatus());
		sysUser.setWorkNumber(userDto.getWorkNumber());
		Boolean flag = this.updateById(sysUser);
		if (flag) {
			return new ResultMoudel(ResultMoudel.SUCCESS_FLAG, "修改成功");
		}
		updateRedis();
		return new ResultMoudel("error", "修改失败");
	}

	@Override
	@CacheEvict(value = "user_details", key = "#username")
	public Boolean updateUser(SysUserDto userDto, String username) {
		SysUser sysUser = new SysUser();
		BeanUtils.copyProperties(userDto, sysUser);
//		sysUser.setDeptId(0);
		sysUser.setUpdateTime(new Date());
		this.updateById(sysUser);

		SysUserRole condition = new SysUserRole();
		condition.setUserId(userDto.getUserId());
		sysUserRoleService.delete(new EntityWrapper<>(condition));
		userDto.getRole().forEach(roleId -> {
			SysUserRole userRole = new SysUserRole();
			userRole.setUserId(sysUser.getUserId());
			userRole.setRoleId(roleId);
			userRole.insert();
		});
		updateRedis();
		return Boolean.TRUE;
	}

	@Override
	public ResultMoudel  login(UserVO userVo) {
		// 得到当前登录人信息
 		Map<String, Object> paramMap = new HashMap<String, Object>();
		paramMap.put("username", userVo.getUsername());
//		paramMap.put("status", CommonConstants.STATUS_NORMAL);
		UserVO selectUser = sysUserMapper.selectUserVoByUsername(paramMap);
		if(null != selectUser){
			log.info("登录人信息selectUser:{}", JSONUtil.toJSON(selectUser));
			log.info("登录人状态信息selectUser.getStatus:{}", selectUser.getStatus());
		}else{
			log.info("《----------------------------用户查询为空-------------------------------》");
            return new ResultMoudel(ResultMoudel.ERROR_FLAG, "未查询到当前登录人信息");
		}

		if(1 == selectUser.getStatus() || selectUser.getDelFlag().equals("1") == true) {
			return new ResultMoudel<>("error", "该用户已经停用");
		}
		// 用户名不存在
		if (null == selectUser) {
			return new ResultMoudel<>("error", "用户名不存在");
		}
		// 校验登录密码是否一致
		String password = userVo.getPassword();
		// 录入密码加密
		String md5Password = MD5.sign(password, null, "utf-8");
		if (!md5Password.equals(selectUser.getPassword())) {
			log.info("登录名userName:{}密码password:{}录入不正确", userVo.getUsername(), password);
			return new ResultMoudel<>("error", "登录名" + userVo.getUsername() + "密码录入错误");
		}
		SysUser sysUser = new SysUser();
		BeanUtils.copyProperties(selectUser,sysUser);
		UserInfo userInfo = new UserInfo();
		userInfo.setSysUser(sysUser);
		//设置岗位信息
		PostUser postUser = new PostUser();
		postUser.setDelFlag(0);
		postUser.setUserId(sysUser.getUserId());
		EntityWrapper<PostUser> postUserEntityWrapper = new EntityWrapper(postUser);
		List<PostUser> postUsers = postUserMapper.selectList(postUserEntityWrapper);
		if(null != postUsers && postUsers.size() > 0){
			List<Integer> PostIds = postUsers.stream().map(e -> e.getPostId()).collect(Collectors.toList());
			userInfo.getSysUser().setPostIds(PostIds);
		}
		//设置公司信息
		Integer companyId = userInfo.getSysUser().getCompanyId();
		if(null != companyId){
			CompanyManager companyManager = companyManagerMapper.selectById(companyId);
			if(null != companyManager){
				Integer delFlag = companyManager.getDelFlag();
				if(0 != delFlag.intValue()){
					return new ResultMoudel<>("error", "企业信息异常");
				}
				Integer status = companyManager.getStatus();
				if(1 == status.intValue()){
					return new ResultMoudel<>("error", "当前企业已经封存");
				}
				userInfo.getSysUser().setCompanyLogo(companyManager.getCompanyLogo());
				userInfo.getSysUser().setCompanyName(companyManager.getCompanyName());
			}
		}
		// 设置角色列表
		List<SysRole> roleList = selectUser.getRoleList();

		List<String> roleNames = new ArrayList<>();
		if (CollectionUtil.isNotEmpty(roleList)) {
			for (SysRole sysRole : roleList) {
				if (!StrUtil.equals(CommonConstants.BASE_ROLE, sysRole.getRoleName())) {
					roleNames.add(sysRole.getRoleName());
				}
			}
		}
		String[] roles = roleNames.toArray(new String[roleNames.size()]);
		userInfo.setRoles(roles);

		// 设置权限列表（menu.permission）
		Set<MenuVO> menuVoSet = new HashSet<>();
		for (String role : roles) {
			List<MenuVO> menuVos = sysMenuService.findMenuByRoleName(role);
			menuVoSet.addAll(menuVos);
		}
		Set<String> permissions = new HashSet<>();
		for (MenuVO menuVo : menuVoSet) {
			if (StringUtils.isNotEmpty(menuVo.getPermission())) {
				String permission = menuVo.getPermission();
				permissions.add(permission);
			}
		}
		userInfo.setPermissions(permissions.toArray(new String[permissions.size()]));

		// 查询当前用户所拥有的数据权限
		Map<String, Object> columMap = new HashMap<String, Object>();
		columMap.put("USER_ID", userInfo.getSysUser().getUserId());
		columMap.put("DEL_FLAG", CommonConstants.DEL_FLAG_NO);
		List<SysUserDataPermission> sysUserDataPermissionList = sysUserDataPermissionMapper.selectByMap(columMap);
		userInfo.setSysUserDataPermissionList(sysUserDataPermissionList);
		//查询当前登录人类型及（政府人员：省市区  机构人员：下属机构）
		//setUserInfo(sysUser);
		log.info("当前登录人userName:{}的基本信息userInfo:{}", userVo.getUsername(), JSONUtil.toJSON(userInfo));
		return new ResultMoudel(ResultMoudel.SUCCESS_FLAG, JSONUtil.toJSON(userInfo));
	}
	
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Override
	public AppResultMoudel loginByApp(UserVO userVo) {
		// 得到当前登录人信息
		 		Map<String, Object> paramMap = new HashMap<String, Object>();
				paramMap.put("username", userVo.getUsername());
				UserVO selectUser = sysUserMapper.selectUserVoByUsername(paramMap);
				if(null != selectUser){
					log.info("登录人信息selectUser:{}", JSONUtil.toJSON(selectUser));
					log.info("登录人状态信息selectUser.getStatus:{}", selectUser.getStatus());
				}else{
					log.info("《----------------------------用户查询为空-------------------------------》");
		            return new AppResultMoudel().error(null, "未查询到当前登录人信息");
				}

				if(0!=selectUser.getStatus()) {
					return new AppResultMoudel().error(null, "该用户已经停用");
				}
				// 用户名不存在
				if (null == selectUser) {
					return new AppResultMoudel().error(null, "用户名不存在");
				}
				// 校验登录密码是否一致
				String password = userVo.getPassword();
				// 录入密码加密
				String md5Password = MD5.sign(password, null, "utf-8");
				if (!md5Password.equals(selectUser.getPassword())) {
					log.info("登录名userName:{}密码password:{}录入不正确", userVo.getUsername(), password);
					return new AppResultMoudel().error(null, "登录名" + userVo.getUsername() + "密码录入错误");
				}
				SysUser sysUser = new SysUser();
				BeanUtils.copyProperties(selectUser,sysUser);
				UserInfo userInfo = new UserInfo();
				userInfo.setSysUser(sysUser);
				//设置岗位信息
				PostUser postUser = new PostUser();
				postUser.setDelFlag(0);
				postUser.setUserId(sysUser.getUserId());
				EntityWrapper<PostUser> postUserEntityWrapper = new EntityWrapper(postUser);
				List<PostUser> postUsers = postUserMapper.selectList(postUserEntityWrapper);
				if(null != postUsers && postUsers.size() > 0){
					List<Integer> PostIds = postUsers.stream().map(e -> e.getPostId()).collect(Collectors.toList());
					userInfo.getSysUser().setPostIds(PostIds);
				}
				//设置公司信息
				Integer companyId = userInfo.getSysUser().getCompanyId();
				if(null != companyId){
					CompanyManager companyManager = companyManagerMapper.selectById(companyId);
					if(null != companyManager){
						Integer delFlag = companyManager.getDelFlag();
						if(0 != delFlag.intValue()){
							return new AppResultMoudel().error(null, "企业信息异常");
						}
						Integer status = companyManager.getStatus();
						if(1 == status.intValue()){
							return new AppResultMoudel().error(null, "当前企业已经封存");
						}
						userInfo.getSysUser().setCompanyLogo(companyManager.getCompanyLogo());
						userInfo.getSysUser().setCompanyName(companyManager.getCompanyName());
					}
				}
				
				log.info("当前登录人userName:{}的基本信息userInfo:{}", userVo.getUsername(), JSONUtil.toJSON(userInfo));
				return new AppResultMoudel().success(JSONUtil.toJSON(userInfo), "登录成功");
	}
	
	
	/**
	 * 功能描述: <br>
	 * 〈登录失败记录登录失败次数，超过次数则不能登录
	 * 手机号登录验证码错3次，该登录方式锁5分钟
	 * 用户名登录有5次机会，如果都错误改登录方式锁5分钟
	 * 已经锁定的用户在5分钟内时间不再重新计算
	 * 〉
	 * @Param:
	 * @Return:
	 * @Author: caifulin
	 * @Date: 2020/5/6
	 */
	public Boolean setRedisLoginErrorLog(Integer loginFlag,UserVO userVo){
		//redis 设置失效时间单位，为秒
		long outTime = CommonConstants.MINUTE_SECOND_5;
		if(loginFlag == 0){
			log.info("《----------------------------用户名登录失败,错误次数加一："+userVo.getUsername()+"-------------------------------》");
			String key = CommonConstants.LOGIN_ERROR_NUM_NAME + userVo.getUsername();
			Object o = redisTemplate.opsForValue().get(key);
			if(null != o){
				Integer nameNum = Integer.valueOf(o.toString());
				nameNum = nameNum + 1;
				String strNameNum = String.valueOf(nameNum);
				if(nameNum > 5){//第5次输入错误则该用户被锁 5分钟
					log.info("《----------------------------用户名登录方式失败次数达到5次，该用户登录方式被锁5分钟-------------------------------》");
					redisTemplate.opsForValue().set(CommonConstants.LOGIN_ERROR_NUM_NAME_LOCK+userVo.getUsername(),strNameNum,outTime,TimeUnit.SECONDS);
					return false;
				}
				log.info("《----------------------------当前用户失败次数为："+nameNum+"-------------------------------》");
				redisTemplate.opsForValue().set(key,strNameNum,outTime,TimeUnit.SECONDS);
			}else{
				log.info("《----------------------------当前用户失败次数为：1 -------------------------------》");
				redisTemplate.opsForValue().set(key,String.valueOf(1),outTime,TimeUnit.SECONDS);
			}
		}else{
			log.info("《----------------------------手机号登录失败，错误次数加一："+userVo.getPhone()+"-------------------------------》");
			String phoneKey = CommonConstants.LOGIN_ERROR_NUM_PHONE + userVo.getPhone();
			Object o = redisTemplate.opsForValue().get(phoneKey);
			if(null != o){
				Integer phoneNum = Integer.valueOf(o.toString());
				phoneNum = phoneNum + 1;
				String strPhoneNum = String.valueOf(phoneNum);
				if(phoneNum > 3){//第3次输入错误则该用户被锁 5分钟
					log.info("《----------------------------手机号登录方式失败次数达到3次，该用户登录方式被锁5分钟-------------------------------》");
					redisTemplate.opsForValue().set(CommonConstants.LOGIN_ERROR_NUM_NAME_LOCK+userVo.getPhone(),strPhoneNum,outTime,TimeUnit.SECONDS);
					return false;
				}
				log.info("《----------------------------当前用户失败次数为："+phoneNum+"-------------------------------》");
				redisTemplate.opsForValue().set(phoneKey,strPhoneNum,outTime,TimeUnit.SECONDS);
			}else{
				log.info("《----------------------------当前用户失败次数为：1 -------------------------------》");
				redisTemplate.opsForValue().set(phoneKey,String.valueOf(1),outTime,TimeUnit.SECONDS);
			}
		}
		return true;
	}
	
	
	public Boolean setRedisInspectionLoginErrorLog(Integer loginFlag,UserVO userVo){
		//redis 设置失效时间单位，为秒
		long outTime = CommonConstants.MINUTE_SECOND_5;
		if(loginFlag == 0){
			log.info("《----------------------------用户名登录失败,错误次数加一："+userVo.getUsername()+"-------------------------------》");
			String key = CommonConstants.INSPECTION_LOGIN_ERROR_NUM_NAME + userVo.getUsername();
			Object o = redisTemplate.opsForValue().get(key);
			if(null != o){
				Integer nameNum = Integer.valueOf(o.toString());
				nameNum = nameNum + 1;
				String strNameNum = String.valueOf(nameNum);
				if(nameNum > 5){//第5次输入错误则该用户被锁 5分钟
					log.info("《----------------------------用户名登录方式失败次数达到5次，该用户登录方式被锁5分钟-------------------------------》");
					redisTemplate.opsForValue().set(CommonConstants.INSPECTION_LOGIN_ERROR_NUM_NAME_LOCK+userVo.getUsername(),strNameNum,outTime,TimeUnit.SECONDS);
					return false;
				}
				log.info("《----------------------------当前用户失败次数为："+nameNum+"-------------------------------》");
				redisTemplate.opsForValue().set(key,strNameNum,outTime,TimeUnit.SECONDS);
			}else{
				log.info("《----------------------------当前用户失败次数为：1 -------------------------------》");
				redisTemplate.opsForValue().set(key,String.valueOf(1),outTime,TimeUnit.SECONDS);
			}
		}else{
			log.info("《----------------------------手机号登录失败，错误次数加一："+userVo.getPhone()+"-------------------------------》");
			String phoneKey = CommonConstants.INSPECTION_LOGIN_ERROR_NUM_PHONE + userVo.getPhone();
			Object o = redisTemplate.opsForValue().get(phoneKey);
			if(null != o){
				Integer phoneNum = Integer.valueOf(o.toString());
				phoneNum = phoneNum + 1;
				String strPhoneNum = String.valueOf(phoneNum);
				if(phoneNum > 3){//第3次输入错误则该用户被锁 5分钟
					log.info("《----------------------------手机号登录方式失败次数达到3次，该用户登录方式被锁5分钟-------------------------------》");
					redisTemplate.opsForValue().set(CommonConstants.INSPECTION_LOGIN_ERROR_NUM_NAME_LOCK+userVo.getPhone(),strPhoneNum,outTime,TimeUnit.SECONDS);
					return false;
				}
				log.info("《----------------------------当前用户失败次数为："+phoneNum+"-------------------------------》");
				redisTemplate.opsForValue().set(phoneKey,strPhoneNum,outTime,TimeUnit.SECONDS);
			}else{
				log.info("《----------------------------当前用户失败次数为：1 -------------------------------》");
				redisTemplate.opsForValue().set(phoneKey,String.valueOf(1),outTime,TimeUnit.SECONDS);
			}
		}
		return true;
	}
	/**
	 * 功能描述: <br>
	 * 〈用户登录时判断用户是否被锁〉
	 * @Param:
	 * @Return:
	 * @Author: caifulin
	 * @Date: 2020/5/7
	 */
	public Boolean existUserLock(Integer loginFlag,UserVO userVo) {
		if (loginFlag == 0) {
			String key = CommonConstants.LOGIN_ERROR_NUM_NAME + userVo.getUsername();
			Object o = redisTemplate.opsForValue().get(key);
			if (null != o) {
				Integer nameNum = Integer.valueOf(o.toString());
				if (nameNum >= 5) {//第5次输入错误则该用户被锁 5分钟
					log.info("《----------------------------该用户已被锁定：" + JSONUtil.toJSON(userVo) + "-------------------------------》");
					return false;
				}
			}
		} else {
			String phoneKey = CommonConstants.LOGIN_ERROR_NUM_PHONE + userVo.getPhone();
			Object o = redisTemplate.opsForValue().get(phoneKey);
			if (null != o) {
				Integer phoneNum = Integer.valueOf(o.toString());
				if (phoneNum >= 3) {//第3次输入错误则该用户被锁 5分钟
					log.info("《----------------------------该用户已被锁定：" + JSONUtil.toJSON(userVo) + "-------------------------------》");
					return false;
				}
			}
		}
		return true;
	}
	
	
	/**
	 * 功能描述: <br>
	 * 〈用户登录时判断用户是否被锁〉
	 * @Param:
	 * @Return:
	 * @Author: caifulin
	 * @Date: 2020/5/7
	 */
	public Boolean inspectionExistUserLock(Integer loginFlag,UserVO userVo) {
		if (loginFlag == 0) {
			String key = CommonConstants.INSPECTION_LOGIN_ERROR_NUM_NAME + userVo.getUsername();
			Object o = redisTemplate.opsForValue().get(key);
			if (null != o) {
				Integer nameNum = Integer.valueOf(o.toString());
				if (nameNum >= 5) {//第5次输入错误则该用户被锁 5分钟
					log.info("《----------------------------该用户已被锁定：" + JSONUtil.toJSON(userVo) + "-------------------------------》");
					return false;
				}
			}
		} else {
			String phoneKey = CommonConstants.INSPECTION_LOGIN_ERROR_NUM_PHONE + userVo.getPhone();
			Object o = redisTemplate.opsForValue().get(phoneKey);
			if (null != o) {
				Integer phoneNum = Integer.valueOf(o.toString());
				if (phoneNum >= 3) {//第3次输入错误则该用户被锁 5分钟
					log.info("《----------------------------该用户已被锁定：" + JSONUtil.toJSON(userVo) + "-------------------------------》");
					return false;
				}
			}
		}
		return true;
	}

	/**
	 * 功能描述: <br>
	 * 〈登录成功后把redis的登录错误数清除〉
	 * @Param:
	 * @Return:
	 * @Author: caifulin
	 * @Date: 2020/5/7
	 */
	public void delRedisLoginErrorLog(Integer loginFlag,UserVO userVo){
		if (loginFlag == 0) {
			String key = CommonConstants.LOGIN_ERROR_NUM_NAME + userVo.getUsername();
			redisTemplate.delete(key);

		} else {
			String phoneKey = CommonConstants.LOGIN_ERROR_NUM_PHONE + userVo.getPhone();
			redisTemplate.delete(phoneKey);
		}
	}
	public void delRedisInspectionLoginErrorLog(Integer loginFlag,UserVO userVo){
		if (loginFlag == 0) {
			String key = CommonConstants.INSPECTION_LOGIN_ERROR_NUM_NAME + userVo.getUsername();
			redisTemplate.delete(key);

		} else {
			String phoneKey = CommonConstants.INSPECTION_LOGIN_ERROR_NUM_PHONE + userVo.getPhone();
			redisTemplate.delete(phoneKey);
		}
	}

	@Override
	public Map<String, String> getUserInfoMap() {
		Map<String, String> ret =  new HashMap<String, String>();
		Map<String,Object> columnMap = new HashMap<String, Object>();
		List<SysUser> sysUserList = sysUserMapper.selectByMap(columnMap);
		for(SysUser vo : sysUserList) {
			ret.put(vo.getUserId().toString(), vo.getName());
		}
		return ret;
	}
	
	@Override
	public void updateRedis() {
		  Map<String, String> redisData = getUserInfoMap();
	      redisTemplate.opsForHash().putAll("userInfoMap", redisData);
	}

	@Override
	public List<SysUser> getUsersByName(Map<String, Object> name) {
		return sysUserMapper.getUsersByName(name);
	}


	@Override
	public ResultMoudel updatePassword(SysUserDto userDto) {
		SysUser user = userService.selectById(userDto.getUserId());
		user.setUpdateTime(new Date());
		if (StrUtil.isNotBlank(userDto.getOldPassword()) && StrUtil.isNotBlank(userDto.getNewpassword1())) {
			if (MD5.sign(userDto.getOldPassword(), null, "utf-8").equals(user.getPassword())) {
				boolean b = RegUtil.checkPassword1(userDto.getNewpassword1());
				if(!b){
					return new ResultMoudel("error", "必须是包含大小写字母、数字、特殊符号的8位以上组合");
				}
				boolean b1 = RegUtil.checkPassword2(userDto.getNewpassword1());
				if(!b1){
					return new ResultMoudel("error", "不能含有3个相同连续字符");
				}
				user.setPassword(MD5.sign(userDto.getNewpassword1(), null, "utf-8"));
			} else {
				log.warn("原密码错误，修改密码失败:{}", user.getUsername());
				return new ResultMoudel("error", "原密码错误，修改失败");
			}
		}
		Integer result = sysUserMapper.updateById(user);
		if (result==1){
			Integer userId = userDto.getUserId();
			Object token = stringRedisTemplate.opsForValue().get(UserConstant.USER_ID_TOKEN_PREFIEX + userId+"_pc");
			stringRedisTemplate.delete(UserConstant.USER_TOKEN_PREFIEX + token);
			stringRedisTemplate.delete(UserConstant.USER_ID_TOKEN_PREFIEX + userId+"_pc");
			return new ResultMoudel(ResultMoudel.SUCCESS_FLAG,"修改密码成功");
		}
		return new ResultMoudel(ResultMoudel.SUCCESS_FLAG,"修改密码失败");
	}

	@Override
	public ResultMoudel sendSms(UserVO userVo) {
		//查询数据 启用的未删除的手机号
		Integer integer = sysUserMapper.existPhone(userVo);
		ResultMoudel resultMoudel = new ResultMoudel();
		if(integer == 0){
			return resultMoudel.error("未查询到对应的手机号");
		}
		log.info("《----------------------------开始发送手机验证码步骤-------------------------------》");
		try {
			String phone =userVo.getPhone();//填写的手机号

			String state = sendSms(phone);//调用短信接口
			log.info("调用短信接口后的返回值：" + state);
			if ("OK".equals(state)) {
				return resultMoudel.success("短信发送成功");
			}else if ("isv.BUSINESS_LIMIT_CONTROL".equals(state)) {
				return resultMoudel.error("短信发送过于频繁,请稍后再试");
			}else {
				return resultMoudel.error("短信发送失败,请稍后重试");
			}
		}catch (Exception e){
			log.info("《----------------------------调用短信接口出现异常：-------------------------------》"+e);
			return resultMoudel.error("服务器出现异常");
		}
	}
	@Override
	public ResultMoudel sendInspectionSms(UserVO userVo) {
		//查询数据 启用的未删除的手机号
		Integer integer = sysUserMapper.existInspectionPhone(userVo);
		ResultMoudel resultMoudel = new ResultMoudel();
		if(integer == 0){
			return resultMoudel.error("未查询到对应的手机号");
		}
		log.info("《----------------------------开始发送手机验证码步骤-------------------------------》");
		try {
			String phone =userVo.getPhone();//填写的手机号

			String state = sendSms(phone);//调用短信接口
			log.info("调用短信接口后的返回值：" + state);
			if ("OK".equals(state)) {
				return resultMoudel.success("短信发送成功");
			}else if ("isv.BUSINESS_LIMIT_CONTROL".equals(state)) {
				return resultMoudel.error("短信发送过于频繁,请稍后再试");
			}else {
				return resultMoudel.error("短信发送失败,请稍后重试");
			}
		}catch (Exception e){
			log.info("《----------------------------调用短信接口出现异常：-------------------------------》"+e);
			return resultMoudel.error("服务器出现异常");
		}
	}


	/**
	 * 功能描述: <br>
	 * 〈发送短信验证码〉
	 * @Param:
	 * @Return:
	 * @Author: caifulin
	 * @Date: 2020/5/8
	 */
	public String sendSms(String phone) throws Exception {
		//设置超时时间-可自行调整
		System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
		System.setProperty("sun.net.client.defaultReadTimeout", "10000");

		//初始化ascClient需要的几个参数
 		final String product = "Dysmsapi";//短信API产品名称（短信产品名固定，无需修改）
		final String domain = "dysmsapi.aliyuncs.com";//短信API产品域名（接口地址固定，无需修改）

		//替换成你的AK
		final String accessKeyId = CommonConstants.ACCESSKEYID;//你的accessKeyId
		final String accessKeySecret = CommonConstants.ACCESSKEYSECRET;//你的accessKeySecret
		//初始化ascClient,暂时不支持多region（请勿修改）
		IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
		DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
		IAcsClient acsClient = new DefaultAcsClient(profile);
		//组装请求对象
		SendSmsRequest request = new SendSmsRequest();
		//使用post提交
		request.setMethod(MethodType.POST);
		//必填:待发送手机号
		request.setPhoneNumbers(phone);
		//必填:短信签名-可在短信控制台中找到
		request.setSignName(CommonConstants.SIGNNAME);
		//必填:短信模板-可在短信控制台中找到，发送国际/港澳台消息时，请使用国际/港澳台短信模版
		request.setTemplateCode(CommonConstants.TEMPLATECODE);
		//随机产生一个6位数的验证码
		String random = (int) ((Math.random() * 9 + 1) * 100000) + "";
		log.info("《----------------------------本次验证码："+random+"-------------------------------》");
		//将生成的6位随机数存入Redis里(规则：key=手机号，value=验证码)，3分钟内有效
		redisTemplate.opsForValue().set(phone,random,CommonConstants.SMS_TIME_OUT, TimeUnit.SECONDS);
		//可选:模板中的变量替换JSON串
		request.setTemplateParam("{\"code\":"+random+"}");
		//请求失败这里会抛ClientException异常
		SendSmsResponse sendSmsResponse = null;
		String code = "";
		try {

			sendSmsResponse = acsClient.getAcsResponse(request);
			if(null != sendSmsResponse){
				code = sendSmsResponse.getCode();
				if(code.equals("isv.OUT_OF_SERVICE")){
					log.info("《----------------------------业务停机-------------------------------》");
					log.info("《----------------------------请先查看账户余额，若余额大于零，则请通过创建工单联系工程师处理-------------------------------》");
				}else if(code.equals("isv.MOBILE_NUMBER_ILLEGAL")){
					log.info("《----------------------------非法手机号:"+phone+"-------------------------------》");
				}else if(code.equals("isv.BLACK_KEY_CONTROL_LIMIT")){
					log.info("《----------------------------黑名单管控" +
							"黑名单管控是指变量内容含有限制发送的内容，变量不支持透传url，同时检查通过变量是否透传了一些敏感信息触发关键字-------------------------------》");
				}
			}
			log.info("《----------------------------信息返回"+JSONUtil.toJSON(sendSmsResponse)+"-------------------------------》");
		} catch (Exception e) {
			return "FAIL";
		} finally {

        }
		if(code.toLowerCase().equals("ok")){
			log.info("《----------------------------信息发送成功-------------------------------》");
		}
		return sendSmsResponse.getCode();
	}
	/**
	 * 功能描述: <br>
	 * 〈通过短信验证码修改密码〉
	 * @Param:
	 * @Return:
	 * @Author: caifulin
	 * @Date: 2020/5/9
	 */
	@Override
	public ResultMoudel updatePasswordByApp(UserVO userVo) {
		//查询该手机号码是否存在
		Integer integer = sysUserMapper.existPhone(userVo);
		ResultMoudel resultMoudel = new ResultMoudel();
		if(integer == 0){
			return resultMoudel.error("未查询到对应的手机号");
		}
		//只要验证码对就可以修改密码
		Object o = redisTemplate.opsForValue().get(userVo.getPhone());
		if(null == o){
			log.info("《----------------------------查询不到redis中的验证码-------------------------------》");
			return resultMoudel.error("验证码超时");
		}else if(o.toString().equals(userVo.getSalt())){
			log.info("《----------------------------验证码匹配成功，修改密码-------------------------------》");
			String password = userVo.getPassword();
			String md5Password = MD5.sign(password, null, "utf-8");
			userVo.setPassword(md5Password);
			Integer integer1 = sysUserMapper.updateAppUserPawword(userVo);
			if(integer1 > 0 ){
				log.info("《----------------------------密码修改成功删除token-------------------------------》");
				Integer userId = userVo.getUserId();
				Object token = redisTemplate.opsForValue().get(UserConstant.USER_ID_TOKEN_PREFIEX + userId + "_app");
				redisTemplate.delete(UserConstant.USER_TOKEN_PREFIEX + token);
				redisTemplate.delete(UserConstant.USER_ID_TOKEN_PREFIEX + userId + "_app");
				return resultMoudel.success("密码修改成功");
			}else {
				return resultMoudel.error("密码修改失败");
			}
		}
		return resultMoudel.error("验证码错误");
	}

	@Override
	public List<SysUser> queryUserByCompanyId(Integer companyId,Map<String,Object> param) {
		SysUser where = new SysUser();
		where.setCompanyId(companyId);
		EntityWrapper entityWrapper = new EntityWrapper(where);
		if(null != param.get("name")){
			entityWrapper.and().like("name",param.get("name").toString());
		}

		List<SysUser> sysUsers = sysUserMapper.selectList(entityWrapper);
		//List<SysUser> sysUsers = this.selectByMap(where);
		return sysUsers;
	}

	@Override
	public ResultMoudel initPassword(UserInfo currentUser, SysUser userDto) {
		ResultMoudel resultMoudel = new ResultMoudel();
		String password = sysUserMapper.queryInitPassword();
		if(null == password){
			password = "bohaiWulian123@bcig.cn";
		}
		String signPassword = MD5.sign(password, null, "utf-8");
		SysUser user = new SysUser();
		user.setPassword(signPassword);
		user.setUpdateTime(new Date());
		user.setUserId(userDto.getUserId());
		Integer integer = sysUserMapper.initPassword(user);
		if(integer == 0 ){
			return  resultMoudel.error("密码初始化失败");
		}
		log.info("《----------------------------清除用户token-------------------------------》");
		Integer userId = userDto.getUserId();
		Object token = stringRedisTemplate.opsForValue().get(UserConstant.USER_ID_TOKEN_PREFIEX + userId+"_pc");
		stringRedisTemplate.delete(UserConstant.USER_TOKEN_PREFIEX + token);
		stringRedisTemplate.delete(UserConstant.USER_ID_TOKEN_PREFIEX + userId+"_pc");
		return resultMoudel.success("密码初始化成功");
	}

	@Override
	public ResultMoudel updateOpenID(SysUser userDto) {
		ResultMoudel resultMoudel = new ResultMoudel();
		Integer integer = sysUserMapper.updateOpenID(userDto);
		if(integer == 0 ){
			return  resultMoudel.error("更新Openid失败");
		}
		return resultMoudel.success("更新Openid成功");
	}
}
